package cn.patpang.core.tool;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author Patrick Pang
 * @Date 2014-8-28
 * @Description 字符串tool
 */
public class StringTool {

	// 国标码和区位码转换常量
	private static final int GB_SP_DIFF = 160;

	// 存放国标一级汉字不同读音的起始区位码
	private static final int[] secPosvalueList = { 1601, 1637, 1833, 2078, 2274, 2302, 2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858, 4027, 4086, 4390, 4558, 4684, 4925, 5249, 5600 };

	// 存放国标一级汉字不同读音的起始区位码对应读音
	private static final char[] firstLetter = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'w', 'x', 'y', 'z' };

	/**
	 * 获取一个汉字的拼音首字母
	 */
	public static char convertFirstLetter(byte[] bytes) {
		char result = '-';
		int secPosvalue = 0;
		int i;
		for (i = 0; i < bytes.length; i++) {
			bytes[i] -= GB_SP_DIFF;
		}
		secPosvalue = bytes[0] * 100 + bytes[1];
		for (i = 0; i < 23; i++) {
			if (secPosvalue >= secPosvalueList[i] && secPosvalue < secPosvalueList[i + 1]) {
				result = firstLetter[i];
				break;
			}
		}
		return result;
	}

	/**
	 * 过滤非法字符 (, ' " { })
	 *
	 * @param str
	 * @return
	 */
	public static String filterLllegalStr(String str) {

		return !StringUtils.isNotBlank(str) ? str : str.replace(",", "，").replace(".", "。").replace("<", "&lt;").replace(">", "&gt;").replace("{", "｛").replace("}", "｝").replace("(", "（").replace("(", "）").replace("[", "【").replace("]", "】").replace("'", "‘").replace("\"", "“");
	}

	/**
	 * 替换换行符
	 *
	 * @param str
	 * @return
	 */
	public static String filterWrapStr(String str) {

		if (StringUtils.isNotBlank(str)) {
			Pattern pattern = Pattern.compile("(\r\n|\r|\n|\n\r)");
			Matcher m = pattern.matcher(str);
			if (m.find()) {
				str = m.replaceAll("");
			}
		}

		return str;
	}

	/**
	 * 拼接sql
	 *
	 * @param conditions
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String joinLikeSql(String[] conditions, List params, String field) {
		String tmpSql = "";
		for (String sk : conditions) {
			if (StringUtils.isNotBlank(sk)) {
				tmpSql += " and " + field + " like ? ";
				params.add("%" + sk.toLowerCase() + "%");
			}
		}
		return tmpSql;
	}

	/**
	 * 去掉空值
	 *
	 * @return
	 */
	public static String clearNull(String[] arr) {
		if (null == arr)
			return null;

		String reStr = "";
		int index = arr.length;
		for (String s : arr) {
			index--;
			if (!StringUtils.isNotBlank(s))
				continue;
			reStr += s;
			if (index > 0) {
				reStr += ",";
			}
		}

		return reStr;
	}

	/**
	 * 是否邮箱格式
	 *
	 * @param email
	 * @return
	 */
	public static boolean isEmailStr(String email) {

		String check = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
		Pattern regex = Pattern.compile(check);
		Matcher matcher = regex.matcher(email);
		boolean isMatched = matcher.matches();
		return isMatched;
	}

	/**
	 * 简单的字符串加密解密 Decryption
	 */
	public static String simpleEncry(String s) {
		String src = "abcdefghijklmnopqrstuvwxyz_-;012345+6789ABCDEFGHIJKLMNOPQRSTUVWXYZ@.=";
		String dest = "v-Wkn8UFzf@IJ6KHw;PM34VrX5NiljOx=dS bc1Y2up7CtaqD.EG_e0LsQmABygRTohZ9";

		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++) {
			sb.append(dest.charAt(src.indexOf(s.charAt(i))));
		}
		return sb.toString();
	}

	public static String simpleDecry(String s) {
		String src = "v-Wkn8UFzf@IJ6KHw;PM34VrX5NiljOx=dS bc1Y2up7CtaqD.EG_e0LsQmABygRTohZ9";
		String dest = "abcdefghijklmnopqrstuvwxyz_-;012345+6789ABCDEFGHIJKLMNOPQRSTUVWXYZ@.=";

		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++) {
			sb.append(dest.charAt(src.indexOf(s.charAt(i))));
		}
		return sb.toString();

	}

	/**
	 * 快速创建map
	 *
	 * @param key
	 * @return
	 */
	public static HashMap<String, Object> simpleMap(String key, Object value) {
		HashMap map = new HashMap();
		map.put(key, value);
		return map;
	}

	/**
	 * 快速创建List
	 *
	 * @param obj
	 * @return
	 */
	public static List simpleList(Object obj) {
		List reList;

		reList = new ArrayList();
		reList.add(obj);

		return reList;
	}

	/**
	 * 汉字 转拼音
	 *
	 * @param src
	 * @return
	 */
	public static String toPinyin(String src) {
		char[] t1 = null;
		t1 = src.toCharArray();
		String[] t2 = new String[t1.length];
		HanyuPinyinOutputFormat t3 = new HanyuPinyinOutputFormat();

		t3.setCaseType(HanyuPinyinCaseType.LOWERCASE);
		t3.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
		t3.setVCharType(HanyuPinyinVCharType.WITH_V);
		String t4 = "";
		int t0 = t1.length;
		try {
			for (int i = 0; i < t0; i++) {
				// 判断是否为汉字字符
				if (Character.toString(t1[i]).matches("[\\u4E00-\\u9FA5]+")) {
					t2 = PinyinHelper.toHanyuPinyinStringArray(t1[i], t3);
					t4 += t2[0];
				} else
					t4 += Character.toString(t1[i]);
			}
			// System.out.println(t4);
			return t4;
		} catch (BadHanyuPinyinOutputFormatCombination e1) {
			e1.printStackTrace();
			return null;
		}
	}

	public static String fristWordUp(String fildeName) throws Exception {
		byte[] items = fildeName.getBytes();
		items[0] = (byte) ((char) items[0] - 'a' + 'A');
		return new String(items);
	}

	/**
	 * 生成支付签名
	 * @date Sep 23, 2015 8:35:46 PM
	 * @param params     支付参数
	 * @param payKey     微信商户支付密钥
	 * @return           签名字符串
	 */
	public static String paySign(Map<String, Object> params, String payKey) {
		//签名步骤一：按字典序排序参数
		String str = toUrlParams(params);
		//签名步骤二：在string后加入KEY
		str = str + "&key=" + payKey;
		//签名步骤三：MD5加密
		str = DigestUtils.md5Hex(str.getBytes());
		//签名步骤四：所有字符转为大写
		str = str.toUpperCase();
		return str;
	}

	/**
	 * 将map参数转为url参数并排序
	 * @date Sep 23, 2015 8:36:18 PM
	 * @param params     map参数
	 * @return           排序后的参数字符串
	 */
	private static String toUrlParams(Map<String, Object> params) {
		List<String> keys = new ArrayList<>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			Object value = params.get(key);

			if (value == null || value.equals("")
					|| key.equalsIgnoreCase("key")
					|| key.equalsIgnoreCase("sign")
					|| key.equalsIgnoreCase("paySign")) {
				continue;
			}

			if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			}
			else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}

	/**
	 * 获取毫秒类型主键，附加七位纳秒值
	 * @return String
	 */
	public static String getKey() {
		DateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String time = format.format(new Date());
		Long curNanos = Math.abs(System.nanoTime());
		String nanos = curNanos.toString();
		return time + nanos.substring(nanos.length() - 7) + getRandomNum(6);
	}

	public static String getSimpleKey(){
		DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
		String time = format.format(new Date());
		return time + getRandomNum(3);
	}

	public static String getBillKey(){
		Long curMillis = System.currentTimeMillis();
		Long curNanos = Math.abs(System.nanoTime());
		String nanos = curNanos.toString();
		return curMillis + nanos.substring(nanos.length() - 6);
	}

	/**
	 * 获取生成单号
	 * @return
	 */
	public static String getCode()
	{
		DateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String time = format.format(new Date());
		return time + getRandomNum(6);
	}

	/**
	 * 获取指定num位随机数字
	 * @author 洪秋霞
	 * @date 2015年8月11日 下午2:22:45
	 * @param num 数字
	 * @return int
	 */
	public static int getRandomNum(int num) {
		int ranNum = 0;
		switch (num) {
			case 3:
				ranNum = (int) ((Math.random() * 9 + 1) * 100);
				break;
			case 4:
				ranNum = (int) ((Math.random() * 9 + 1) * 1000);
				break;
			case 5:
				ranNum = (int) ((Math.random() * 9 + 1) * 10000);
				break;
			default:
				ranNum = (int) ((Math.random() * 9 + 1) * 100000);
				break;
		}
		return ranNum;
	}


	private static int getRandom(int count) {
		return (int) Math.round(Math.random() * (count));
	}

	private static String string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";

	public static String getRandomString(int length){
		StringBuffer sb = new StringBuffer();
		int len = string.length();
		for (int i = 0; i < length; i++) {
			sb.append(string.charAt(getRandom(len-1)));
		}
		return sb.toString();
	}

	public static Integer countStr(String str, char c){
		int count=0;
		for(int i=0;i<str.length();i++){
			if(str.charAt(i)== c){
				count++;
			}
		}
		return count;
	}

	public static String appendStr(List<Object> list, String op){
		String str, operator;

		if (StringUtils.isBlank(op)){
			op = ",";
		}

		operator = op;

		str = list.stream().map(now ->
				now + operator
		).reduce("", (a, b) -> a + b);

		str = str.substring(0, str.lastIndexOf(operator));

		return str;
	}

	public static String getIP(HttpServletRequest request) {
		String ip;

		/*
		 * HTTP代理或者负载均衡服务器时才会添加该项 格式为X-Forwarded-For:client1,proxy1,proxy2
		 * 一般情况下，第一个ip为客户端真实ip，后面的为经过的代理服务器ip 现在大部分的代理都会加上这个请求头 如 nginx +
		 * tomcat形式
		 */
		ip = request.getHeader("x-forwarded-for");

		/*
		 * 经过apache http服务器的请求才会有，用apache
		 * http做代理时一般会加上Proxy-Client-IP请求头，而WL-Proxy-Client-IP是他的weblogic插件加上的头
		 */
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}

		/* TCP/IP 协议中的ip地址 获取到的可能是代理的ip而不是客户端的ip */
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}

		if (StringUtils.isNotBlank(ip)) {
			ip = ip.split(",")[0];
		}

		return ip;
	}
}
